/**
 * CMOSTEK Sub-G 射频芯片 SPI 接口驱动
 * Copyright (c) 2021 深圳市智辰科技有限公司
 * All rights reserved.
 */

#include "nonos.h"
#include "cmtspi3.h"

// 默认延时
#define DELAY() mcu_delay_us(10)
// GPIO 操作
#define SCLK(x) (dev->sclk(x))
#define CSB(x)  (dev->csb(x))
#define FCSB(x) (dev->fcsb(x))
#define DOUT(x) (dev->dout(x))
#define DIN()   (dev->din())
#define GPIO()  (dev->gpio())

void cmtspi3_delay(void) {
    uint32_t n = 7;
    while(n--);
}

void cmtspi3_delay_us(void) {
    uint16_t n = 8;
    while(n--);
}

void cmtspi3_init(driver_cmtspi3_t *dev) {
    CSB(1);		/* CSB has an internal pull-up resistor */    
    SCLK(0);   	/* SCLK has an internal pull-down resistor */    
    DOUT(1);    
    FCSB(1);  	/* FCSB has an internal pull-up resistor */
    cmtspi3_delay();
}

void cmtspi3_tx(driver_cmtspi3_t *dev, uint8_t ch) {
    for(uint8_t i=0; i<8; i++) {
		// 本端在 SCLK 下降沿后送出数据(高位在前)
        SCLK(0);
		if(ch & 0x80) {
			DOUT(1);
		} else {
			DOUT(0);
		}
        cmtspi3_delay();

        // 对端在上升沿读取数据
        SCLK(1);
        cmtspi3_delay();
		
		// 准备发送下一个 bit
        ch <<= 1;
    }
}

uint8_t cmtspi3_rx(driver_cmtspi3_t *dev) {
    uint8_t ch = 0xFF;

    for(uint8_t i=0; i<8; i++) {
        SCLK(0);
        cmtspi3_delay();
        ch <<= 1;

        SCLK(1);

        /* Read byte on the rising edge of SCLK */
        if(DIN()) {
            ch |= 0x01;
        } else {
            ch &= 0xFE;
		}

        cmtspi3_delay();
    }

    return ch;
}

void cmtspi3_write_reg(driver_cmtspi3_t *dev, uint8_t addr, uint8_t ch) {
    DOUT(1);
    SCLK(0);
    FCSB(1);
    CSB(0);

    /* > 0.5 SCLK cycle */
    cmtspi3_delay();
    cmtspi3_delay();

    /* r/w = 0 */
    cmtspi3_tx(dev, addr & 0x7F);
    cmtspi3_tx(dev, ch);

    SCLK(0);

    /* > 0.5 SCLK cycle */
    cmtspi3_delay();
    cmtspi3_delay();

    CSB(1);    
    DOUT(1);
    DIN();    
    FCSB(1);    
}

uint8_t cmtspi3_read_reg(driver_cmtspi3_t *dev, uint8_t addr) {
    DOUT(1);
    SCLK(0);
    FCSB(1);
    CSB(0);

    /* > 0.5 SCLK cycle */
    cmtspi3_delay();
    cmtspi3_delay();

    /* r/w = 1 */
    cmtspi3_tx(dev, addr|0x80);

    /* Must set SDIO to input before the falling edge of SCLK */
    DIN();
    
    uint8_t ch = cmtspi3_rx(dev);

    SCLK(0);

    /* > 0.5 SCLK cycle */
    cmtspi3_delay();
    cmtspi3_delay();

    CSB(1);    
    DOUT(1);
    DIN();    
    FCSB(1);
	
	return ch;
}

void cmtspi3_write_fifo(driver_cmtspi3_t *dev, const uint8_t* buf, uint16_t len) {
    FCSB(1);
    CSB(1);
    SCLK(0);
    DOUT(0);

    for(uint16_t i=0; i<len; i++) {
        FCSB(0);

        /* > 1 SCLK cycle */
        cmtspi3_delay();
        cmtspi3_delay();

        cmtspi3_tx(dev, buf[i]);

        SCLK(0);

        /* > 2 us */
        cmtspi3_delay_us();
        cmtspi3_delay_us();
        cmtspi3_delay_us();

        FCSB(1);

        /* > 4 us */
        cmtspi3_delay_us();
        cmtspi3_delay_us();
        cmtspi3_delay_us();
        cmtspi3_delay_us();
        cmtspi3_delay_us();
        cmtspi3_delay_us();
    }

    DIN();    
    FCSB(1);
}

void cmtspi3_read_fifo(driver_cmtspi3_t *dev, uint8_t* buf, uint16_t len) {
    FCSB(1);
    CSB(1);
    SCLK(0);
    DIN();

    for(uint16_t i=0; i<len; i++) {
        FCSB(0);

        /* > 1 SCLK cycle */
        cmtspi3_delay();
        cmtspi3_delay();

        buf[i] = cmtspi3_rx(dev);

        SCLK(0);

        /* > 2 us */
        cmtspi3_delay_us();
        cmtspi3_delay_us();
        cmtspi3_delay_us();

        FCSB(1);

        /* > 4 us */
        cmtspi3_delay_us();
        cmtspi3_delay_us();
        cmtspi3_delay_us();
        cmtspi3_delay_us();
        cmtspi3_delay_us();
        cmtspi3_delay_us();
    }

    DIN();    
    FCSB(1);
}

void cmtspi3_test0(driver_cmtspi3_t *dev) {
	uint8_t buf[32];
	cmtspi3_init(dev);
	cmtspi3_write_reg(dev, 0x38, 0x79);
	buf[0] = cmtspi3_read_reg(dev, 0x38);
	loghex(buf, 1);
}

void cmtspi3_test(driver_cmtspi3_t *dev) {
	uint8_t buf[32];
	cmtspi3_read_fifo(dev, buf, 32);
	loghex(buf, 32);
	
	uint8_t regs[0x72];
	for(uint8_t i=0; i<0x72; i++) {
		regs[i] = cmtspi3_read_reg(dev, i);
	}
	loghex(regs, 0x72);
}
